package uk.ac.manchester.tewpl.iceiface.client.explorer.ui;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import uk.ac.manchester.tewpl.iceiface.client.Functors.ParamVoidCallback;
import uk.ac.manchester.tewpl.iceiface.client.Functors.VoidCallback;
import uk.ac.manchester.tewpl.iceiface.client.explorer.Explorer;
import uk.ac.manchester.tewpl.iceiface.client.explorer.Utils;
import uk.ac.manchester.tewpl.iceiface.client.explorer.events.AddAirportToJourneyEvent;
import uk.ac.manchester.tewpl.iceiface.client.explorer.events.ChangeSelectedAirportEvent;
import uk.ac.manchester.tewpl.iceiface.client.explorer.events.ExplorerEvent;
import uk.ac.manchester.tewpl.iceiface.client.explorer.events.InitEvent;
import uk.ac.manchester.tewpl.iceiface.client.explorer.events.ResetEvent;
import uk.ac.manchester.tewpl.iceiface.client.explorer.events.UpdatedResultsEvent;
import uk.ac.manchester.tewpl.iceiface.client.explorer.nodes.Airport;
import uk.ac.manchester.tewpl.iceiface.client.explorer.types.Mutable;
import uk.ac.manchester.tewpl.iceiface.client.explorer.types.Route;
import uk.ac.manchester.tewpl.iceiface.client.explorer.types.Uri;
import uk.ac.manchester.tewpl.iceiface.client.model.KBIndividualModel;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.Style.Scroll;
import com.extjs.gxt.ui.client.data.BaseModelData;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.util.Margins;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.layout.MarginData;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.toolbar.FillToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.LabelToolItem;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.widgetideas.graphics.client.Color;

public class SidePanel extends UI {
	
	// Explorer
	private Explorer explorer;
	
	// Initialisation variables
	private boolean initialised = false;
	
	// Retrieve variables
	private Collection<Airport> airports = Registry.get("airports");
	private Mutable<Airport> airportSelected = Registry.get("airportSelected");
	private LinkedList<Airport> journey = Registry.get("journey");
	private ArrayList<KBIndividualModel> timePeriods = Registry.get("timePeriods");
	private Utils utils = Registry.get("utils");
	
	// Detail panel objects
	private LayoutContainer airportPanelsContainer = new LayoutContainer();
	private LayoutContainer forwardRoutesContainer = new LayoutContainer();
	private Collection<AirportPanel> airportPanels = new ArrayList<AirportPanel>();
	
	public SidePanel(Explorer expl) {
		explorer = expl;
		// Configure panel
		this.setHeaderVisible(true);
		this.setHeading("Filters");
		this.setScrollMode(Scroll.AUTOY);
		
		// Fiters panel toolbar
		ToolBar filterToolBar = new ToolBar();
		this.setTopComponent(filterToolBar);
		filterToolBar.add(new LabelToolItem("Time Period:"));
		filterToolBar.add(new FillToolItem());
		
		// Time period list store
		ListStore<KBIndividualModel> timePeriodStore = new ListStore<KBIndividualModel>();
		
		// Add time periods
		timePeriodStore.add(timePeriods);
		
		// Time period combo box
		ComboBox<KBIndividualModel> timePeriodCombo = new ComboBox<KBIndividualModel>();
		timePeriodCombo.setDisplayField("label");
		timePeriodCombo.setAllowBlank(false);
		timePeriodCombo.setStore(timePeriodStore);

		filterToolBar.add(timePeriodCombo);
		
	}

	@Override
	public void init(VoidCallback onFinishCallback) {
		// Add containers
		this.add(airportPanelsContainer);
		this.add(forwardRoutesContainer);//, new RowData(1,0, new Margins(0,0,6,0)));
		
		// Set CSS style
		forwardRoutesContainer.setStyleName("forward-routes-container");
		
		// Done initialising
		initialised = true;
		onFinishCallback.work();
	}

	
	public void handle(ExplorerEvent event) {
		if (event.getClass() == InitEvent.class) {
			updateForwardRoutes();
		} else if (event.getClass() == ResetEvent.class) {
			clearAirportPanels();
			updateForwardRoutes();
		} else if (event.getClass() == AddAirportToJourneyEvent.class) {
			addAirportPanel(((AddAirportToJourneyEvent) event).getAirport());
			updateForwardRoutes();
		}		
		this.layout();
	}
	
	private void updateForwardRoutes() {
		// Clear container
		forwardRoutesContainer.removeAll();
		
		MarginData marginData = new MarginData(6,10,0,6);
		
		// Container for the filter name & number
		LayoutContainer forwardRoutesTitle = new LayoutContainer();
		forwardRoutesTitle.setStyleName("forward-routes-title");
		
		// Add title
		forwardRoutesContainer.add(forwardRoutesTitle, marginData);
		
		Collection<Uri> destinations = new HashSet<Uri>();

		if (journey.size() == 0) {
			forwardRoutesTitle.add(new Text("Select an airport:"));
			for (Airport airport : airports)
				destinations.add(airport.getUri());
		} else {
			for (Uri uri : journey.getLast().getDestinations()) {
				Airport destination = utils.getCachedAirport(uri);
				// If destination exists on map, and hasn't already been visited, draw the route
				if (utils.getCachedAirport(uri) != null	&& !journey.contains(destination)) {
					destinations.add(uri);
				} // if
			} // for
			
			if (destinations.size() > 0)
				forwardRoutesTitle.add(new Text("Forward Routes:"));
		}
		
		// Render forward routes
		if (destinations.size() > 0) {
			// Add forward routes
			for (Uri uri : destinations) {
				final Airport dest = utils.getCachedAirport(uri);
				if (dest != null) {
					// Container for the filter detail
					LayoutContainerMouse forwardRouteContainer = new LayoutContainerMouse();
					String baseStyle = "forward-routes-line-format forward-route";
					forwardRouteContainer.setStyleName(baseStyle);
					
					// Add the forward route
					forwardRouteContainer.add(new Text(dest.getLabel() + " (" + dest.getCount() + ")"));
					
					// Add mouse handlers
					forwardRouteContainer.addMouseHoverStyler(baseStyle, "forward-route-hover");
					forwardRouteContainer.addMouseDownHandler(new MouseDownHandler() {
						@Override
						public void onMouseDown(MouseDownEvent arg0) {
							explorer.addAirportToJourney(dest);
						}
					});
					
					// Add filter details to filter container
					forwardRoutesContainer.add(forwardRouteContainer, marginData);
				}
			} // for
		} // if
		
		this.layout();
	}
	
	/*
	 * Add airport details panel
	 */
	private void addAirportPanel(final Airport airport) {
		// Initialise panel
		final AirportPanel panel = new AirportPanel(airport, airportPanels.size() + 1);
		airportPanels.add(panel);
		
		// Add panel to GUI and refresh layout
		airportPanelsContainer.add(panel, new RowData(1,0, new Margins(0,0,6,0)));
	}
	
	/*
	 * Find the AirportPanel for a corresponding airport
	 */
	private AirportPanel getAirportPanel(Airport airport) {
		for (AirportPanel panel : airportPanels) { // For each added panel
			if (panel.equals(airport)) { // Found panel matching 'airport'
				return panel;
			}
		}
		return null;
	}
	
	/*
	 * Remove the AirportPanel for a given Airport from display
	 */
	private void removeAirportPanel(Airport airport) {
		AirportPanel panel = getAirportPanel(airport);
		if (panel != null) {
			airportPanelsContainer.remove(panel);
			airportPanels.remove(panel);
			this.layout();
		}
	}
	
	/*
	 * Remove all AirportPanels from display
	 */
	private void clearAirportPanels() {
		for (AirportPanel panel : airportPanels)
			airportPanelsContainer.remove(panel);
		airportPanels.clear();
		this.layout();
	}
	
}
